
/*Copyright (C) 2011  Jens Schwarzhaupt

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.*/

package de.dhbw.GpsTools;
/**The class provides methods to calculate with gps-waypoints.
 * For example the distance between two waypoints.
 * @author Jens Schwarzhaupt
 *
 */
public class GpsCalculator {
	
	private Waypoint waypoint1;
	private Waypoint waypoint2;
	
	/**Standardconstructor
	 * 
	 */
	public GpsCalculator(){
		
	}
	
	/**Constructor that gets two waypoints you want to calculate with.
	 * 
	 * @param wpt1 The first waypoint.
	 * @param wpt2 The second waypoint.
	 */
	public GpsCalculator( Waypoint wpt1, Waypoint wpt2){
		waypoint1 = wpt1;
		waypoint2 = wpt2;
	}
	
	/**Set the first waypoint.
	 * 
	 * @param wpt1 The first waypoint you want to calculate with.
	 */
	public void setWaypoint1(Waypoint wpt1){
		waypoint1 = wpt1;
	}
	
	/**Get the first waypoint.
	 * 
	 * @return The first waypoint.
	 */
	public Waypoint getWaypoint1() {
		return waypoint1;
	}

	/**Set the second waypoint.
	 * 
	 * @param wpt2 The second waypoint you want to calculate with.
	 */
	public void setWaypoint2(Waypoint wpt2) {
		waypoint2 = wpt2;
	}

	/**Get the second waypoint.
	 * 
	 * @return The second waypoint.
	 */
	public Waypoint getWaypoint2(){
		return waypoint2;
	}
	
	/**Get the distance between two waypoints.
	 * This method can only be used if the waypoints were passed with the constructor
	 * or with the explicit methods. 
	 * 
	 * @return The distance between two waypoints in meters.
	 */
	public double getDistance(){
		double lon1 = Math.toRadians(waypoint1.getLongitude());
		double lon2 = Math.toRadians(waypoint2.getLongitude());
		double lat1 = Math.toRadians(waypoint1.getLatitude());
		double lat2 = Math.toRadians(waypoint2.getLatitude());
		
		double s1 = Math.cos(lon1)*Math.cos(lon2)*Math.sin(lat1)*Math.sin(lat2);
		double s2 = Math.sin(lon1)*Math.sin(lon2)*Math.sin(lat1)*Math.sin(lat2);
		double s3 = Math.cos(lat1)*Math.cos(lat2);
		
		double alpha = Math.acos(s1+s2+s3);
		double distance = 40024000*(Math.abs(alpha)/(2*Math.PI));
		if (Double.isNaN(distance)){
			distance = 0.0;
		}
		return distance;
	}
	
	/**Get the distance between two waypoints.
	 * 
	 * @param wpt1 The first waypoint you want to calculate with.
	 * @param wpt2 The second waypoint you want to calculate with.
	 * @return The distance between two waypoints in meters.
	 */
	public double getDistance(Waypoint wpt1, Waypoint wpt2){
		double lon1 = Math.toRadians(wpt1.getLongitude());
		double lon2 = Math.toRadians(wpt2.getLongitude());
		double lat1 = Math.toRadians(wpt1.getLatitude()+90);
		double lat2 = Math.toRadians(wpt2.getLatitude()+90);
		
		double s1 = Math.cos(lon1)*Math.cos(lon2)*Math.sin(lat1)*Math.sin(lat2);
		double s2 = Math.sin(lon1)*Math.sin(lon2)*Math.sin(lat1)*Math.sin(lat2);
		double s3 = Math.cos(lat1)*Math.cos(lat2);
		
		double alpha = Math.acos(s1+s2+s3);
		double distance = 40024000*(Math.abs(alpha)/(2*Math.PI));
		if (Double.isNaN(distance)){
			distance = 0.0;
		}
		return distance;
	}
	
	/**Get the approximated distance between two waypoints. (DONT USE IT IF YOU DONT KNOW WHAT YOU DO!)
	 * 
	 * @param wpt1 The first waypoint you want to calculate with.
	 * @param wpt2 The second waypoint you want to calculate with.
	 * @return The distance between two waypoints in meters.
	 */
	public double getDistanceAppr(Waypoint wpt1, Waypoint wpt2){
		
		double delta_lat = (wpt1.getLatitude() - wpt2.getLatitude()) * 111000;
		double delta_lon = (wpt1.getLongitude() - wpt2.getLongitude()) * 70000;
		
		double distance = Math.sqrt(delta_lon*delta_lon + delta_lat*delta_lat);
		if (Double.isNaN(distance)){
			distance = 0.0;
		}
		return distance;
	}
	
	/**Get the distance between two gps-coordinates.
	 * 
	 * @param lon1 The longitude of the first coordinate
	 * @param lat1 The latitude of the first coordinate
	 * @param lon2 The longitude of the second coordinate 
	 * @param lat2 The latitude of the second coordinate
	 * @return The distance between two gps-coordinates in meters
	 */
	public double getDistance(double lon1, double lat1, double lon2, double lat2){
		lon1 = Math.toRadians(lon1);
		lat1 = Math.toRadians(lat1+90);
		lon2 = Math.toRadians(lon2);
		lat2 = Math.toRadians(lat2+90);
		double s1 = Math.cos(lon1)*Math.cos(lon2)*Math.sin(lat1)*Math.sin(lat2);
		double s2 = Math.sin(lon1)*Math.sin(lon2)*Math.sin(lat1)*Math.sin(lat2);
		double s3 = Math.cos(lat1)*Math.cos(lat2);
		
		double alpha = Math.acos(s1+s2+s3);
		double distance = 40024000*(Math.abs(alpha)/(2*Math.PI));
		if (Double.isNaN(distance)){
			distance = 0.0;
		}
		return distance;
	}
	
	/**Get the elevation distance between two waypoints.
	 * This method can only be used if the waypoints were passed with the constructor
	 * or with the explicit methods. 
	 * 
	 * @return The elevation distance between two waypoints in meters.
	 */
	public double getElevationDifference(){
		return  waypoint2.getElevation()-waypoint1.getElevation();
	}
	
	/**Get the elevation distance between two waypoints.
	 * 
	 * @param wpt1 The first waypoint you want to calculate with.
	 * @param wpt2 The second waypoint you want to calculate with.
	 * @return The elevation distance between two waypoints in meters.
	 */
	public double getElevationDifference(Waypoint wpt1, Waypoint wpt2){
		return  wpt2.getElevation()-wpt1.getElevation();
	}
	
	/**Get the duration between two waypoints.
	 * This method can only be used if the waypoints were passed with the constructor
	 * or with the explicit methods. 
	 * @return The duration between two waypoints in milliseconds.
	 */
	public long getDuration(){
		return waypoint2.getTime().getTime()-waypoint1.getTime().getTime();
	}
	
	/**Get the duration between two waypoints.
	 * 
	 * @param wpt1 The first waypoint you want to calculate with.
	 * @param wpt2 The second waypoint you want to calculate with.
	 * @return The duration between two waypoints in milliseconds.
	 */
	public long getDuration(Waypoint wpt1, Waypoint wpt2){
		return wpt2.getTime().getTime()-wpt1.getTime().getTime();
	}
}